package com.vshop.platform.system.listener;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.vshop.framework.core.constant.Const;
import com.vshop.framework.core.util.MapstructUtil;
import com.vshop.framework.core.util.ServletUtil;
import com.vshop.framework.core.util.ip.IpAddressUtil;
import com.vshop.framework.log.event.LogLoginEvent;
import com.vshop.framework.log.event.LogOperEvent;
import com.vshop.framework.mybatisflex.listener.EntityListenerManager;
import com.vshop.framework.satoken.helper.LoginHelper;
import com.vshop.platform.system.crud.service.SysClientService;
import com.vshop.platform.system.crud.service.SysLoginLogService;
import com.vshop.platform.system.crud.service.SysOperLogService;
import com.vshop.platform.system.domain.param.SysLoginLogParam;
import com.vshop.platform.system.domain.param.SysOperLogParam;
import com.vshop.platform.system.domain.vo.SysClientVo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Slf4j
@Component
public class LogEventListener {

    private final SysClientService clientService;
    private final SysLoginLogService loginLogService;
    private final SysOperLogService operLogService;


    /**
     * 操作日志记录
     *
     * @param logOperEvent 操作日志事件
     */
    @Async
    @EventListener
    public void onLogOperEvent(LogOperEvent logOperEvent) {
//        log.info("LogOperEvent: {}", logOperEvent);
        SysOperLogParam operLog = MapstructUtil.convert(logOperEvent, SysOperLogParam.class);
        // 远程查询操作地点
        operLog.setOperLocation(IpAddressUtil.getRealAddressByIP(operLog.getOperIp()));

        // 不执行 插入数据 InsertListener
        EntityListenerManager.withoutInsertListener(() -> {
            operLogService.save(operLog);
        });
    }

    /**
     * 记录登录信息
     *
     * @param logLoginEvent 登录事件
     */
    @Async
    @EventListener
    public void onLogLoginEvent(LogLoginEvent logLoginEvent) {
//        log.info("LogLoginEvent: {}", logLoginEvent);
        HttpServletRequest request = logLoginEvent.getRequest();
        final UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent(request));
        final String ip = ServletUtil.getClientIP(request);
        // 客户端信息
        String clientId = request.getHeader(LoginHelper.ClientIdKey);
        SysClientVo client = null;
        if (StrUtil.isNotBlank(clientId)) {
            client = clientService.getByClientId(clientId);
        }

        String address = IpAddressUtil.getRealAddressByIP(ip);
        String s = getBlock(ip) +
                address +
                getBlock(logLoginEvent.getUsername()) +
                getBlock(logLoginEvent.getStatus()) +
                getBlock(logLoginEvent.getMessage());
        // 打印信息到日志
        log.info(s, logLoginEvent.getArgs());
        // 获取客户端操作系统
        String os = userAgent.getOs().getName();
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        // 封装对象
        SysLoginLogParam logLoginParam = new SysLoginLogParam();
        logLoginParam.setTenantId(logLoginEvent.getTenantId());
        logLoginParam.setUserName(logLoginEvent.getUsername());
        if (ObjectUtil.isNotNull(client)) {
            logLoginParam.setClientKey(client.getClientKey());
            logLoginParam.setDeviceType(client.getDeviceType());
        }
        logLoginParam.setIp(ip);
        logLoginParam.setIpLocation(address);
        logLoginParam.setBrowser(browser);
        logLoginParam.setOs(os);
        logLoginParam.setMsg(logLoginEvent.getMessage());
        // 日志状态
        if (StringUtils.equalsAny(logLoginEvent.getStatus(), Const.LoginSuccess, Const.Logout, Const.Register)) {
            logLoginParam.setStatus(Const.Success);
        } else if (Const.LoginError.equals(logLoginEvent.getStatus())) {
            logLoginParam.setStatus(Const.Error);
        }

        // 不执行 插入数据 InsertListener
        EntityListenerManager.withoutInsertListener(() -> {
            loginLogService.save(logLoginParam);
        });
    }

    private String getBlock(Object msg) {
        if (msg == null) {
            msg = "";
        }
        return "[" + msg.toString() + "]";
    }

}
